package pubsub

import (
	"encoding/json"
	"gitee.com/liukexing/mqbroker/core/driver/logger"
	"gitee.com/liukexing/mqbroker/core/typedef"
	"time"
)

func initCommand() {
	Server.NewPublisher("command", Server.GetPubConfig(), "command")
	Server.NewSubscriber("command", Server.GetSubConfig(), "command")
}

type CommandServerHandle struct {
	CommonMsger
	Command      map[string]typedef.CommonMsgConfig
	CustSubCheck func(*CommonMsgHandle, typedef.CommonMsg) bool
	CustCompute  func(*CommonMsgHandle, typedef.CommonMsg) (map[string]interface{}, bool)
	CustPack     func(*CommonMsgHandle, typedef.CommonMsg, map[string]interface{}) (typedef.CommonMsg, bool)
	CustPubCheck func(*CommonMsgHandle, typedef.CommonMsg, typedef.CommonMsg) bool
	CustMsgPub   func(*CommonMsgHandle, typedef.CommonMsg)
}

func (c *CommandServerHandle) SubCheck(m *CommonMsgHandle, data typedef.CommonMsg) bool {
	if c.CustSubCheck != nil {
		return c.CustSubCheck(m, data)
	}
	//MsgType Check
	if !(data.MsgType == m.SubMsgType) {
		return true
	}

	msg := typedef.CommandRequest{}
	if err := typedef.Decode(data.Message, &msg); err != nil {
		return true
	}
	if v, ok := c.Command[msg.Cmd]; ok {
		//Sender Check
		if v.Sub.Sender != "" && data.Sender != v.Sub.Sender {
			return true
		}
		//Receiver Check
		if v.Sub.Receiver != "" && data.Receiver != v.Sub.Receiver {
			return true
		}
		return false
	}
	return true
}

func (c *CommandServerHandle) Compute(m *CommonMsgHandle, data typedef.CommonMsg) (map[string]interface{}, bool) {
	if c.CustCompute != nil {
		return c.CustCompute(m, data)
	}
	req := typedef.CommandRequest{}
	result := make(map[string]interface{})
	if err := typedef.Decode(data.Message, &req); err != nil {
		return result, true
	}
	if v, ok := c.Command[req.Cmd]; ok {
		fv, err := v.Handle(req.Args)
		return fv, logger.CheckErr(typedef.ErrInfo{
			Info: Config.Info,
			Err:  err,
		})
	}
	return result, true
}

func (c *CommandServerHandle) Pack(m *CommonMsgHandle, data typedef.CommonMsg, response map[string]interface{}) (typedef.CommonMsg, bool) {
	if c.CustPack != nil {
		return c.CustPack(m, data, response)
	}
	req := typedef.CommandRequest{}
	if err := typedef.Decode(data.Message, &req); err != nil {
		return typedef.CommonMsg{}, logger.CheckErr(typedef.ErrInfo{
			Info: Config.Info,
			Err:  err,
		})
	}
	return typedef.CommonMsg{
		Sender:   m.Sender,
		SendTime: time.Now(),
		Receiver: data.Sender,
		MsgType:  m.PubMsgType,
		Message: typedef.CommandResponse{
			ReqID:    req.ReqID,
			Response: response,
		},
	}, false
}

func (c *CommandServerHandle) PubCheck(m *CommonMsgHandle, data typedef.CommonMsg, resp typedef.CommonMsg) bool {
	if c.CustPubCheck != nil {
		return c.CustPubCheck(m, data, resp)
	}
	//MsgType Check
	if resp.MsgType != m.PubMsgType {
		return true
	}
	msg := typedef.CommandRequest{}
	if err := typedef.Decode(data.Message, &msg); err != nil {
		return true
	}
	if v, ok := c.Command[msg.Cmd]; ok {
		//Sender Check
		if v.Pub.Sender != "" && resp.Sender != v.Pub.Sender {
			return true
		}
		//Receiver Check
		if v.Pub.Receiver != "" && resp.Receiver != v.Pub.Receiver {
			return true
		}
		return false
	}
	return true
}

func (c *CommandServerHandle) MsgPub(m *CommonMsgHandle, resp typedef.CommonMsg) {
	if c.CustMsgPub != nil {
		c.CustMsgPub(m, resp)
		return
	}
	if jsv, err := json.Marshal(resp); err == nil {
		Server.Publish(m.PubTopic, string(jsv))
	}
}

type CommandClientHandle struct {
	CommonMsger
	MsgReceiver func(string, typedef.CommandResponse)
}

func (c *CommandClientHandle) SubCheck(m *CommonMsgHandle, data typedef.CommonMsg) bool {
	//MsgType Check
	if data.MsgType != m.SubMsgType {
		return true
	}
	if m.Sender != "" && data.Receiver != m.Sender {
		return true
	}
	return false
}

func (c *CommandClientHandle) Compute(m *CommonMsgHandle, data typedef.CommonMsg) (map[string]interface{}, bool) {
	rsp := typedef.CommandResponse{}
	result := make(map[string]interface{})
	if err := typedef.Decode(data.Message, &rsp); err != nil {
		return result, true
	}
	c.MsgReceiver(data.Sender, rsp)
	return result, true
}

func (c *CommandClientHandle) Pack(m *CommonMsgHandle, data typedef.CommonMsg, response map[string]interface{}) (typedef.CommonMsg, bool) {
	return typedef.CommonMsg{}, true
}

func (c *CommandClientHandle) PubCheck(m *CommonMsgHandle, data typedef.CommonMsg, resp typedef.CommonMsg) bool {
	return true
}

func (c *CommandClientHandle) MsgPub(m *CommonMsgHandle, resp typedef.CommonMsg) {
	return
}

func CommandMsgPub(sender, receiver, cmd string, arg map[string]interface{}) (string, bool) {
	reqid := typedef.GetUUID()
	msg := typedef.CommonMsg{
		Sender:   sender,
		SendTime: time.Now(),
		Receiver: receiver,
		MsgType:  "CommandRequest",
		Message: typedef.CommandRequest{
			Cmd:   cmd,
			ReqID: reqid,
			Args:  arg,
		},
	}
	if jsv, err := json.Marshal(msg); err == nil {
		return reqid, Server.Publish("command", string(jsv))
	}
	return reqid, true
}

func CommandMsgSubServer(info typedef.ModuleInfo, handle *CommandServerHandle) bool {
	return Server.AddSubscriber(info.ID+"_server", "command", &CommonMsgHandle{
		PubTopic:   "command",
		SubMsgType: "CommandRequest",
		PubMsgType: "CommandResponse",
		Sender:     info.ID,
		Handle:     handle,
	})
}

func CommandMsgUnSubServer(info typedef.ModuleInfo) bool {
	return Server.RemoveSubscriber(info.ID+"_server", "command")
}

func CommandMsgSubClient(info typedef.ModuleInfo, msgreceiver func(string, typedef.CommandResponse)) bool {
	return Server.AddSubscriber(info.ID+"_client", "command", &CommonMsgHandle{
		SubMsgType: "CommandResponse",
		Sender:     info.ID,
		Handle: &CommandClientHandle{
			MsgReceiver: msgreceiver,
		},
	})
}

func CommandMsgUnSubClient(info typedef.ModuleInfo) bool {
	return Server.RemoveSubscriber(info.ID+"_client", "command")
}
